﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace GeometryMod.Models
{
    /// <summary>
    /// M00 M01
    /// M10 M11
    /// </summary>
    public class Matrix2x2
    {
        #region ///properties

        public const int ROW = 2;
        public const int COLUMN = 2;

        public float M00
        {
            get { return dataArr[0, 0]; }
            set { dataArr[0, 0] = value; }
        }

        public float M01
        {
            get { return dataArr[0, 1]; }
            set { dataArr[0, 1] = value; }
        }

        public float M10
        {
            get { return dataArr[1, 0]; }
            set { dataArr[1, 0] = value; }
        }

        public float M11
        {
            get { return dataArr[1, 1]; }
            set { dataArr[1, 1] = value; }
        }

        private float[,] dataArr = new float[ROW, COLUMN];

        public Vector2 Row0 { get { return new Vector2(M00, M01); } }
        public Vector2 Row1 { get { return new Vector2(M10, M11); } }
        public Vector2 Column0 { get { return new Vector2(M00, M10); } }
        public Vector2 Column1 { get { return new Vector2(M01, M11); } }
        #endregion

        public float this[int row, int col]
        {
            get { return dataArr[row, col]; }
            set { dataArr[row, col] = value; }
        }

        public Matrix2x2() { }

        public Matrix2x2(float m00, float m01, float m10, float m11)
        {
            M00 = m00;
            M01 = m01;

            M10 = m10;
            M11 = m11;
        }
        /// <summary>
        /// xy基向量
        /// 竖向排列
        /// </summary>
        /// <param name="ax"></param>
        /// <param name="ay"></param>
        public Matrix2x2(Vector2 ax, Vector2 ay)
        {
            M00 = ax.X;
            M10 = ax.Y;

            M10 = ay.X;
            M11 = ay.Y;
        }
        /// <summary>
        /// 2*2数组
        /// </summary>
        /// <param name="arr"></param>
        public Matrix2x2(float[,] arr)
        {
            M00 = arr[0, 0];
            M01 = arr[0, 1];

            M10 = arr[1, 0];
            M11 = arr[1, 1];
        }
        /// <summary>
        /// 矩阵*vector2
        /// </summary>
        /// <param name="m2x2"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        public static Vector2 operator *(Matrix2x2 m2x2, Vector2 v2)
        {
            float x = Vector2.Dot(m2x2.Row0, v2);
            float y = Vector2.Dot(m2x2.Row1, v2);
            return new Vector2(x, y);
        }
        /// <summary>
        /// 矩阵*矩阵
        /// </summary>
        /// <param name="m2x2a"></param>
        /// <param name="m2x2b"></param>
        /// <returns></returns>
        public static Matrix2x2 operator *(Matrix2x2 m2x2a, Matrix2x2 m2x2b)
        {
            float c00 = Vector2.Dot(m2x2a.Row0, m2x2b.Column0);
            float c01 = Vector2.Dot(m2x2a.Row0, m2x2b.Column1);

            float c10 = Vector2.Dot(m2x2a.Row1, m2x2b.Column0);
            float c11 = Vector2.Dot(m2x2a.Row1, m2x2b.Column1);

            Matrix2x2 ret = new Matrix2x2(c00, c01, c10, c11);
            return ret;
        }
        /// <summary>
        /// 矩阵/标量
        /// </summary>
        /// <param name="m2x2"></param>
        /// <param name="f"></param>
        /// <returns></returns>
        public static Matrix2x2 operator /(Matrix2x2 m2x2, float f)
        {
            for (int x = 0; x < ROW; x++)
            {
                for (int y = 0; y < COLUMN; y++)
                {
                    m2x2[x, y] /= f;
                }
            }
            return m2x2;
        }
        /// <summary>
        /// 行列式
        /// </summary>
        /// <returns></returns>
        public float GetDeterminant()
        {
            float det = M00 * M11 - M01 * M10;
            return det;
        }
        /// <summary>
        /// 求转置矩阵
        /// </summary>
        /// <returns></returns>
        public Matrix2x2 GetTransposeMatrix()
        {
            Matrix2x2 m2x2T = new Matrix2x2();
            for (int x = 0; x < ROW; x++)
            {
                for (int y = 0; y < COLUMN; y++)
                {
                    m2x2T[x, y] = this[y, x];
                }
            }
            return m2x2T;
        }
        /// <summary>
        /// 求余子式标量
        /// </summary>
        /// <param name="r"></param>
        /// <param name="c"></param>
        /// <returns></returns>
        public float GetCofactorScalar(int r, int c)
        {
            float cof = 0f;
            for (int x = 0; x < ROW; x++)
            {
                for (int y = 0; y < COLUMN; y++)
                {
                    if (x != r && y != c)
                    {
                        cof = dataArr[x, y];
                        break;
                    }
                }
            }
            return cof;
        }
        /// <summary>
        /// 求余子式标量矩阵
        /// + -
        /// - +
        /// </summary>
        /// <returns></returns>
        public Matrix2x2 GetCofactorScalarMatrix()
        {
            Matrix2x2 m2x2 = new Matrix2x2();
            for (int x = 0; x < ROW; x++)
            {
                for (int y = 0; y < COLUMN; y++)
                {
                    float cof = GetCofactorScalar(x, y);
                    bool ispostive = (x + y) % 2 == 0;
                    m2x2[x, y] = ispostive ? cof : -cof;
                }
            }
            return m2x2;
        }
        /// <summary>
        /// 求伴随矩阵
        /// 算法：余子式标量矩阵的转置
        /// </summary>
        /// <returns></returns>
        public Matrix2x2 GetAdjointMatrix()
        {
            Matrix2x2 m2x2 = GetCofactorScalarMatrix();
            Matrix2x2 m2x2T = m2x2.GetTransposeMatrix();
            return m2x2T;
        }
        /// <summary>
        /// 求逆矩阵
        /// 算法：伴随矩阵/行列式值
        /// </summary>
        /// <returns></returns>
        public Matrix2x2 GetInverseMatrix()
        {
            Matrix2x2 m2x2 = GetAdjointMatrix();
            float det = GetDeterminant();
            Matrix2x2 m2x2I = m2x2 / det;
            return m2x2I;
        }

        public override string ToString()
        {
            string ret = $"换行\nM00:{M00} M01:{M01} \nM10:{M10} M11:{M11}";
            return ret;
        }
    }
}
